import {
    MeshLambertMaterial,
    Mesh,
    Vector3,
    SphereGeometry,
    LineBasicMaterial,
    Line,
    BufferGeometry,
    CatmullRomCurve3
} from 'three';

export default class LineChart {
    public group: Mesh;
    private smooth: boolean;
    private noLine: boolean;

    constructor(data: any[] = [], manifest: Manifest) {
        const { smooth = false, noLine = false } = manifest;
        this.smooth = smooth;
        this.noLine = noLine;
        this.group = new Mesh();
        data.forEach((item) => {
            const { color, dataArr } = item;
            const pointPosArr = this.getPosArr(dataArr);
            if (!this.noLine) {
                const lineMesh = this.drawLine(color, pointPosArr);
                this.group.add(lineMesh);
            }


            dataArr.forEach((cur: any, i: number) => {
                const { perWidth } = cur;
                const pointMesh = this.drawPoint(color, i, perWidth, pointPosArr[i])
                this.group.add(pointMesh);
            })
            this.group.position.x = -0.2;
        });
    }
    private drawLine(color: number, pointPosArr: any[]) {
        const points = pointPosArr.reduce((acc: Vector3[], cur: any) => {
            const x = cur[0];
            const y = cur[1];
            const z = cur[2];
            acc.push(new Vector3(x, y, z))
            return acc;
        }, []);
        // 线
        const lineGeo = new BufferGeometry();
        const curve = new CatmullRomCurve3(points);
        let length = pointPosArr.length - 1;
        if (this.smooth) {
            length *= 10000;
        }
        const pointsArr = curve.getPoints(length);

        lineGeo.setFromPoints(pointsArr);
        const lineMaterial = new LineBasicMaterial({ color })
        const lineMesh = new Line(lineGeo, lineMaterial);

        return lineMesh;
    }

    private drawPoint(color: number, index: number, perWidth: number, point: any) {
        // 点
        const pointGeo = new SphereGeometry(perWidth / 5 * 2, 32, 32)
        const pointMaterial = new MeshLambertMaterial({ color, depthTest: true });
        const pointMesh = new Mesh(pointGeo, pointMaterial)
        pointMesh.position.x = point[0];
        pointMesh.position.y = point[1];
        pointMesh.position.z = point[2];
        return pointMesh;
    }

    private getPosArr(data: any) {
        const arr = data.reduce((acc: any, cur: any, index: number) => {
            const { perWidth, quantY, quantZ = 0 } = cur;
            acc.push([perWidth * 2 * index, quantY, quantZ]);
            return acc;
        }, [])
        return arr;
    }
}
